<template>
  <a-modal
    :title="$t('languages.Apps.FormDesignPage.Calculation')"
    :visible="true"
    width="612px"
    :cancelText="$t('languages.Apps.Cancel')"
    :okText="$t('languages.Apps.Ok')"
    @cancel="closeModal"
    @ok="backData"
    :maskClosable="false"
    :keyboard="false"
  >
    <div class="calculate-rule">
      <div class="data-item clearfix">
        <div class="title">
          <span>{{ $t('languages.Apps.FormDesignPage.DataItem') }}:</span>
        </div>
        <div>
          <a-select
            class="select"
            :placeholder="$t('languages.PlaceHolder.Select')"
            @change="dataItemChange"
          >
            <a-select-option
              v-for="(dataitem, i) in dataItems"
              :key="i"
              :value="dataitem.code"
            >{{ `${dataitem.name}[${dataitem.code}]` }}</a-select-option>
          </a-select>
        </div>
        <div>
          <a-button @click="pushDataItem">{{ $t('languages.Apps.FormDesignPage.Insert') }}</a-button>
        </div>
      </div>
      <div class="btn-group">
        <ul class="clearfix">
          <li v-for="(symbol, i) in symbolList" :key="i" @click="symbolBtnClick(symbol)">
            <a-button>{{ symbol }}</a-button>
          </li>
        </ul>
      </div>
      <div class="btn-group">
        <ul class="clearfix sum">
          <li v-for="(rule, i) in ruleList" :key="i" @click="ruleBtnClick(rule)">
            <a-button>{{ rule }}</a-button>
          </li>
        </ul>
      </div>
      <div class="text-area">
        <a-textarea
          v-model="ruleString"
          ref="ruletextarea"
          @click="getCursorIndex"
          @change="getCursorIndex"
        ></a-textarea>
      </div>
    </div>
  </a-modal>
</template>
<script lang="ts">
import { Component, Vue, Emit, Prop } from "vue-property-decorator";

import * as dataitemStore from "../stores/data-items.store-helper";

@Component({
  name: "CalculateRule"
})
export default class CalculateRule extends Vue {
  @Prop({
    type: Object
  })
  modalData!: any;
  /** 全部的 */
  /**
   * notUsed 未使用
   */
  get dataItemCodeList() {
    const codeArr: any[] = [];
    const length: number = this.items.length;
    for (let i = 0; i < length; i += 1) {
      codeArr.push(this.items[i].code);
    }
    return codeArr;
  }
  get items() {
    // const initiallyArr = dataitemStore
    //   .getDataItems(this)
    //   .filter((res: any) => res.published);
    // 取消只显示发布后的数据项
    const initiallyArr = dataitemStore.getDataItems(this);
    const dataArr = JSON.parse(JSON.stringify(initiallyArr));
    const targetArr: any[] = [];
    const length: number = dataArr.length | 0;
    for (let i = 0; i < length; i += 1) {
      targetArr.push(dataArr[i]);
      if (dataArr[i].type === 8 && dataArr[i].properties) {
        const parentCode: string = dataArr[i].code;
        const subDataItem = dataArr[i].properties as any;
        const subLength: number = subDataItem.length | 0;
        for (let j = 0; j < subLength; j += 1) {
          subDataItem[j].code = `${parentCode}.${subDataItem[j].code}`;
          targetArr.push(subDataItem[j]);
        }
      }
    }
    return targetArr.filter((res: any) => res.type === 2);
  }
  ruleList: Array<string> = ["SUM", "AVG", "MAX", "MIN", "COUNT"];
  symbolList: Array<string> = ["+", "-", "*", "/", "(", ")"];
  ruleString: string = "";
  textArea: any = null;
  cursorIndex: any = null;
  dataItems: Array<Apps.Datamodel.DataItem> = [];
  selectDataItem: string = "";
  created() {
    this.dataItems = this.items as any;
    /**
     * 赋予默认值
     */
    const data = this.modalData.data;
    if (data && data.value) {
      // this.ruleString = this.modalData.data.expressionObject.ruleString;
      this.ruleString = data.value;
    }
  }
  mounted() {
    this.textArea = this.$refs.ruletextarea;
  }
  /**
   * 数据项切换
   */
  dataItemChange(val: any) {
    this.selectDataItem = val;
  }
  /**
   * 将数据推送到工公式
   */
  pushDataItem() {
    if (this.selectDataItem) {
      let cursorIndex: number = 0;
      const strStart: string = this.ruleString.slice(0, this.cursorIndex);
      const strEnd: string = this.ruleString.slice(this.cursorIndex);
      this.ruleString = `${strStart}{${this.selectDataItem}}${strEnd}`;
      cursorIndex = strStart.length + this.selectDataItem.length + 2;
      setTimeout(() => {
        this.setCursorPosition(this.textArea.$el, cursorIndex);
        this.getCursorIndex();
      }, 10);
    }
  }
  symbolBtnClick(symbol: string) {
    let cursorIndex: number = 0;
    if (this.cursorIndex && this.cursorIndex !== null) {
      const strStart: string = this.ruleString.slice(0, this.cursorIndex);
      const strEnd: string = this.ruleString.slice(this.cursorIndex);
      this.ruleString = `${strStart}${symbol}${strEnd}`;
      cursorIndex = strStart.length + symbol.length;
    } else {
      this.ruleString = `${this.ruleString}${symbol}`;
      cursorIndex = this.ruleString.length;
    }
    setTimeout(() => {
      this.setCursorPosition(this.textArea.$el, cursorIndex);
      this.getCursorIndex();
    }, 10);
  }
  /**
   * 设置光标位置
   */
  setCursorPosition(ctrl: any, pos: any) {
    if (ctrl.setSelectionRange) {
      ctrl.focus();
      ctrl.setSelectionRange(pos, pos);
    } else if (ctrl.createTextRange) {
      const range = ctrl.createTextRange();
      range.collapse(true);
      range.moveEnd("character", pos);
      range.moveStart("character", pos);
      range.select();
    }
  }
  /**
   * 添加计算按钮
   */
  ruleBtnClick(rule: string) {
    const ruleStr = rule.toLowerCase();
    let cursorIndex: number = 0;
    if (this.cursorIndex && this.cursorIndex !== null) {
      const strStart: string = this.ruleString.slice(0, this.cursorIndex);
      const strEnd: string = this.ruleString.slice(this.cursorIndex);
      this.ruleString = `${strStart}${ruleStr}()${strEnd}`;
      cursorIndex = strStart.length + ruleStr.length + 2;
    } else {
      this.ruleString = `${this.ruleString}${ruleStr}()`;
      cursorIndex = this.ruleString.length;
    }
    setTimeout(() => {
      this.setCursorPosition(this.textArea.$el, cursorIndex - 1);
      this.getCursorIndex();
    }, 10);
  }
  /**
   * 获取鼠标光标下标
   */
  getCursorIndex() {
    this.cursorIndex = this.textArea.$el.selectionStart;
    console.log(this.textArea.$el.selectionStart);
  }
  backData() {
    if (!this.testRuleString(this.ruleString) && this.ruleString) {
      this.$message.error("计算规则不合法");
      return;
    }
    const backData = {
      value: this.ruleString
    };
    this.$emit("backData", backData);
  }
  closeModal() {
    this.$emit("closeModal");
  }
  /**
   * 计算规则的校验
   */
  testRuleString(str: string) {
    // 聚合函数
    const obj: any = {
      sum: 1,
      avg: 1,
      max: 1,
      min: 1,
      count: 1
    };

    // 剔除空白符
    str = str.replace(/\s/g, "");

    // 错误情况，空字符串
    if (!str) {
      return false;
    }

    // 错误情况，运算符连续
    if (/[\+\-\*\/]{2,}/.test(str)) {
      return false;
    }

    // 错误情况，数据项连续 {}{}
    // if (/\}\{/.test(str)) {
    //   return false;
    // }

    // 空括号
    if (/\(\)/.test(str)) {
      return false;
    }

    // 错误情况，括号不配对
    const stack: any[] = [];
    for (let i = 0, item; i < str.length; i += 1) {
      item = str.charAt(i);
      if ("(" === item) {
        stack.push("(");
      } else if (")" === item) {
        if (stack.length > 0) {
          stack.pop();
        } else {
          return false;
        }
      }
    }
    if (0 !== stack.length) {
      return false;
    }

    // 错误情况，(后面是运算符
    if (/\([\+\-\*\/]/.test(str)) {
      return false;
    }

    // 错误情况，)前面是运算符
    if (/[\+\-\*\/]\)/.test(str)) {
      return false;
    }
    //花括号为空
    if (/\{\}/.test(str)) {
      return false;
    }
    //错误情况，花括号不配对
    const bstack: any[] = [];
    for (let i = 0, bitem; i < str.length; i++) {
      bitem = str.charAt(i);
      if ("{" === bitem) {
        bstack.push("{");
      } else if ("}" === bitem) {
        if (bstack.length > 0) {
          bstack.pop();
        } else {
          return false;
        }
      }
    }
    if (0 !== bstack.length) {
      return false;
    }
    // 错误情况，变量没有来自“待选公式变量”
    var tmpStr = str
      .replace(/\{.*?\}/g, "")
      .replace(/[\{\}\(\)\+\-\*\/]{1,}/g, "`");
    var array = tmpStr.split("`");
    for (var i = 0, item; i < array.length; i++) {
      item = array[i];
      if (/[A-Z]/i.test(item) && "undefined" === typeof obj[item]) {
        return false;
      }
    }
    //提取code,检查code 是否存在（已发布）
    const codeStack: any[] = [];
    const arr: any = str.match(/\{(.+?)\}/g);
    const arrCode = this.dataItemCodeList;
    for (var j = 0, len = arr.length; j < len; j++) {
      const strTwo: string = arr[j].replace(/^\{|\}$/g, "");
      if (arrCode.indexOf(strTwo) === -1) {
        return false;
      }
      codeStack.push(strTwo);
    }
    //TODO 数组codeStack 处理，调用接口
    console.log(codeStack);
    return true;
  }
}
</script>
<style lang="less" scoped>
.calculate-rule {
  .data-item {
    margin-bottom: 16px;
    & > div {
      float: left;
      .select {
        width: 308px;
        margin: 0 8px;
      }
    }
    /deep/.title {
      span {
        line-height: 32px !important;
      }
    }
  }
  .btn-group {
    margin-bottom: 16px;
    ul {
      &.sum {
        li {
          button {
            width: 56px;
          }
        }
      }
      li {
        float: left;
        margin-right: 16px;
        /deep/ button {
          padding: 0;
          width: 32px;
          text-align: center;
          span {
            line-height: 32px;
          }
        }
      }
    }
  }
  .text-area {
    textarea {
      width: 100%;
      height: 142px;
      border-radius: 4px;
    }
  }
}
</style>
